#include <string.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <netdb.h>
#include <string.h>
#include <sys/un.h> 
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <fcntl.h>
#include <netinet/in.h> 
#include <arpa/inet.h>
#include <sys/mman.h>
#include <sys/stat.h>
#include <sys/ipc.h>
#include <sys/shm.h>
#include <sys/time.h>
#include <sys/wait.h>
#include <sys/select.h>
#include <math.h>

#include "estructuras.h"
#include "constantes.h"
#include "estadisticas.h"
#include "cache.h"
#include "listas.h"
#include "sockets.h"
#include "configuracion.h"
#include "CSCAN.h"
#include "NIPC.h"
#include "recibirComando.h"



void configToCHS();
chs getCHS(); 
void intacad ( int n , char* cadena); 

   
extern ListConfig * listaConfig;

int main()
{
	int fd, offset;
	char *aux;
	int i,len,t,fdmax;
	char data_sector[512];
	char* read;
	int escucha_consola, Sock_consola;
	struct sockaddr_un local, remote;
	int key;
	int shmid;
	int iSocketConectado,iMayorSocket,iSocketDePedido;
	char *sAux;
	int puertoRAID;
	char* cadena;
	InfoIPC rInfoIPC;
	InfoIPC HS;
	InfoIPC respuestaHS;
	fd_set master;
	fd_set read_fds;
	struct sockaddr_in sin;
	char *payload;
	pid_t child;
	struct stat sbuf;

	
	sAux=(char *)malloc(200);
	read=malloc(512);
	algoritmo=malloc(10);
	
    
    listaConfig = NULL;
    cargarConfig(); 
    printf("\nCargando Archivo de Configuracion...\n\n");
    printf("Path_SocketConsola %s \n",obtenerValor("path"));
    printf("Modo %s \n",obtenerValor("modo"));
	strcpy(algoritmo,obtenerValor("alg"));
    printf("Algoritmo %s \n",algoritmo);
    printf("Puerto %s \n",obtenerValor("puerto"));
    printf("Ip %s \n",obtenerValor("ip"));
    printf("Flag_Log %s \n",obtenerValor("flag_Log"));
    printf("Id_Disco %s \n",obtenerValor("id_Disco"));
    printf("CHS %s \n",obtenerValor("CHS"));
    printf("T_Lectura %s \n",obtenerValor("t_Lectura"));
    printf("T_Escritura %s \n",obtenerValor("t_Escritura"));
    printf("RPM %s \n",obtenerValor("RPM"));
    printf("T_Salto %s \n",obtenerValor("t_Salto"));
	printf("ipRAID %s \n",obtenerValor("ipRAID"));
	puertoRAID=atoi(obtenerValor("puertoRAID"));
	printf("Puerto RAID %i \n",puertoRAID);
	
	configToCHS();	
	
	printf("glChs.cilindros %i \n",glChs.cilindros);
	printf("glChs.cabezal %i \n",glChs.cabezal);
	printf("glChs.sectores %i \n",glChs.sectores);
	sectores_totales_vda = sectoresTotales(getCHS());
	printf("Los sectores totales son %i \n",sectores_totales_vda);
	glCache = atoi(obtenerValor("cache"));
	
	if(glCache == 1)
	{
		iniciarCache(); 
		glTiempoCache = atof(obtenerValor("tiempoCache"));
	}
	glRPM = atoi(obtenerValor("RPM"));
	
	
	/*
	key=atoi(obtenerValor("key"));
    
    if ((shmid = shmget((key_t)key, SHM_SIZE, 0666 | IPC_CREAT)) == -1) {
        perror("shmget");
        exit(1);
    }
    posicionCabezal = shmat(shmid, (void *)0, 0);
    if (posicionCabezal == (int *)(-1)) {
        perror("shmat");
        exit(1);
    }
	*/
	
	posicionCabezal=0;
	
	

	if ((fd = open("/home/utn_so/tp/fat32.disk", O_RDWR)) == -1) {
        perror("open");
        exit(1);
    }
    if (fstat(fd, &sbuf) < 0) {
        perror("fstat");
        exit(1);
    }
    
	data = mmap(0, sbuf.st_size, PROT_READ|PROT_WRITE, MAP_SHARED, fd, 0); 
	strcpy(data_sector,"Esta es una prueba definitiva?");
	
	strcpy(read,readSector(4000));	
	for(i=0;i<512;i++){
		printf("%c",read[i]);
	}
	
	printf("\n");
	
	strcpy(data_sector,"Ojala esta prueba tambien funcione xD");
	writeSector(5000,data_sector);
	strcpy(read,readSector(5000));
	for(i=0;i<512;i++){
		printf("%c",read[i]);
	}
	
	printf("\n"); 

	/*CONECTARSE A RAID
		
	iSocketConectado = crearSocket(AF_INET);
	Conectar2(iSocketConectado,obtenerValor("ipRAID"),atoi(obtenerValor("puertoRAID")));	
	
	HS.payLoadLength=0;
	strcpy(HS.descriptorID,GenerarDescriptor());
	HS.payLoadDescriptor=VDA;
	enviarIPC(iSocketConectado,&HS);

	recibirIPC(iSocketConectado,&respuestaHS);
	
	if(respuestaHS.payLoadDescriptor== HSOK){
	
		payload=(char *)malloc(5);
		strcpy(payload,"VDA1");
		generarStructIPC(payload,NUEVO_DA,&rInfoIPC);
		enviarIPC(iSocketConectado,&rInfoIPC);

		intacad(glChs.cilindros,sAux);
		generarStructIPC(sAux,NUEVO_DA,&rInfoIPC);
		enviarIPC(iSocketConectado,&rInfoIPC);
		
		intacad(glChs.cabezal,sAux);
		generarStructIPC(sAux,NUEVO_DA,&rInfoIPC);
		enviarIPC(iSocketConectado,&rInfoIPC);
		
		intacad(glChs.sectores, sAux);
		generarStructIPC(sAux,NUEVO_DA,&rInfoIPC);
		enviarIPC(iSocketConectado,&rInfoIPC);
		
		recibirIPC(iSocketConectado,&respuestaHS);

		switch(respuestaHS.payLoadDescriptor)
		{
			case DA_INCOMPATIBLE:
					printf("DA incompatible con el que se quiere conectar\n");
					return 0;
					break;

			case MAX_CANTIDAD_DE_DA:
				printf("El proceso al que se quiere conectar no admite mas DA\n");
				return 0;
				break;

			case ERROR_EN_PARAMETROS:
				printf("Hubo un erro al separa los parametros que se pasaron \n");
				return 0;
				break;

			case DA_CONECTADO_CORRECTAMENTE:
				printf("El DA se conecto correctamente \n");
				break;

			default:
				printf("No se recibio msj valido \n");
				return 0;
				break;
				
		}

	}
	*/
	
  
	/*************************************************/
	/*************** CREAR Y CONECTAR ****************/
	/***************     CONSOLA      ****************/
	/*************************************************/
   
	
   if ((escucha_consola = socket(AF_UNIX, SOCK_STREAM, 0)) == -1) {
        printf("error a crear sockent\n\n");
        exit(EXIT_FAILURE);
   }

	local.sun_family = AF_UNIX;
	strcpy(local.sun_path,"sock_consola");
	unlink(local.sun_path);
		
    len = strlen(local.sun_path) + sizeof(local.sun_family);
    if (bind(escucha_consola, (struct sockaddr *)&local, len) == -1) {
        perror("bind");
		exit(EXIT_FAILURE);
    }
	
    if (listen(escucha_consola, 5) == -1) {
        perror("listen");
		exit(EXIT_FAILURE);
    }
	
	/* fork y exec de proceso consola */
	
   if((child=fork())==-1){
		perror("fork");
		exit(EXIT_FAILURE);    
    }
    else if (child==0){
		execv("./consola",NULL);	
    }
	
	t = sizeof(remote);
	if ((Sock_consola = accept(escucha_consola, (struct sockaddr *)&remote, &t)) == -1) {
			perror("accept");
			exit(EXIT_FAILURE);
	}
   
   FD_ZERO(&master);
	FD_SET(Sock_consola,&master);
	   
	if( Sock_consola > fdmax)
		fdmax = Sock_consola;	
      
	
	
   /******************************************************/
	/*************** ESCUCHAR EN MULTIPLES ****************/
	/***************	SOCKET EN EL SELECT	****************/
	/******************************************************/
 

   while(1)
	{
      FD_ZERO(&master);
      FD_SET(Sock_consola, &master);
      FD_SET(iSocketConectado, &master);
      /*
	  if(iSocketConectado > Sock_consola)
         iMayorSocket = iSocketConectado;
      else
      */   iMayorSocket = Sock_consola;

      select(iMayorSocket + 1 , &master, NULL, NULL, NULL);	

      if(FD_ISSET(Sock_consola,&master))
         recibircomando(Sock_consola);	
	/*		
      if( FD_ISSET(iSocketConectado , &master ) > 0 ){
         
		 recibirIPC(iSocketConectado,&rInfoIPC);
         switch( rInfoIPC.payLoadDescriptor )
         {
            case GET_SECTORES:
			
               generarStructIPC("proximamanteread",RTA_GET_SECTORES,&rInfoIPC);
               enviarIPC(iSocketDePedido,&rInfoIPC);
               break;
      
            case PUT_SECTORES:
            
               generarStructIPC("proximamanterwrite",RTA_GET_SECTORES,&rInfoIPC);
               enviarIPC(iSocketDePedido,&rInfoIPC);
               break;

            default:
               printf("NO VALIDO \n");
               break;
 
         }
      }
	  */
   }
   
   Cerrar(Sock_consola);
   Cerrar(iSocketConectado);
   
   return 0;

}



void configToCHS()
{
	/* No recibe parámetros y devuelve tres enteros correspondientes a la información física obtenida de archivo de configuración. */
	char* ntok;
	char* chsAux;
	chs resultadoChs;
	
	chsAux = (char*)malloc(strlen(obtenerValor("CHS"))+1);
	strcpy(chsAux,obtenerValor("CHS"));

	resultadoChs.cilindros = atoi(strtok(chsAux,","));
	resultadoChs.cabezal = atoi(strtok(NULL,","));
	resultadoChs.sectores = atoi(strtok(NULL,","));
	
	glChs = resultadoChs;
}

chs getCHS()
{
	return glChs;
}





void intacad ( int n , char* cadena)
{	
    int j=0;
    int i=0;
	char aux;

	do
    {
		cadena[i] = (n % 10) + '0';    
		n=n/10;
		i++;
	}while (n > 0);

    cadena[i] = '\0';
    i--;

	while(i>j)
	{
		aux=cadena[i];
		cadena[i]=cadena[j];
		cadena[j]=aux;
		i--;
		j++;
	}

}









